package com.tckdq.tcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.tckdq.tcc.constants.MQConstants;
import com.tckdq.tcc.constants.RedisConstant;
import com.tckdq.tcc.doc.CourseDoc;
import com.tckdq.tcc.domain.*;
import com.tckdq.tcc.dto.CourseAddDto;
import com.tckdq.tcc.dto.CourseDetailDto;
import com.tckdq.tcc.dto.StationMessage2MQDto;
import com.tckdq.tcc.exception.GlobalException;
import com.tckdq.tcc.feign.MediaFeign;
import com.tckdq.tcc.feign.SearchFeignClient;
import com.tckdq.tcc.mapper.CourseMapper;
import com.tckdq.tcc.mapper.TeacherMapper;
import com.tckdq.tcc.result.JsonResult;
import com.tckdq.tcc.service.*;
import com.tckdq.tcc.utils.AssertUtil;
import com.tckdq.tcc.utils.StrUtils;
import com.tckdq.tcc.vo.CourseDataForOrderVO;
import com.tckdq.tcc.vo.CourseOrderDataitemVO;
import com.tckdq.tcc.vo.CourseStateVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale
 * @since 2022-08-16
 */
@Service
@Transactional
@Slf4j
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private TeacherMapper teacherMapper;
    @Autowired
    private ICourseMarketService marketService;
    @Autowired
    private ICourseDetailService detailService;
    @Autowired
    private ICourseResourceService resourceService;
    @Autowired
    private ICourseSummaryService summaryService;
    @Autowired
    private ICourseTeacherService courseTeacherService;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private SearchFeignClient searchFeignClient;
    @Autowired
    private RocketMQTemplate mQTemplate;
    @Autowired
    private ICourseChapterService chapterService;
    @Autowired
    private MediaFeign mediaFeignClient;
    /*个人中心的课程+推荐code*/
    @Autowired
    private ICourseUserLearnService learnService;
    @Autowired
    private ICourseRecommendService courseRecommendService;
    @Override
    public JsonResult listForUser() {
        //查询课程
        List<Course> courses = courseMapper.selectList(null);
        String redisInvCode = (String)redisTemplate.opsForValue().get(RedisConstant.INVITATION_CODE + 1L);
        if (!StringUtils.isEmpty(redisInvCode)){
            return JsonResult.success(courses,redisInvCode);
        }
        String invitationCode = StrUtils.getRandomString(4);
        redisTemplate.opsForValue().set(RedisConstant.INVITATION_CODE+1L,invitationCode);

        return JsonResult.success(courses,invitationCode);
    }
    /*
    校验课程名字是否重复
    * 保存课程表 course
    * courseDetail
    * courseMarket
    * courseResource
    * teacharIds
    * */
    @Override
    @Transactional
    public void save(CourseAddDto ourseAddDto) {
        Course course = ourseAddDto.getCourse();
        CourseDetail courseDetail = ourseAddDto.getCourseDetail();
        CourseMarket courseMarket = ourseAddDto.getCourseMarket();
        CourseResource courseResource = ourseAddDto.getCourseResource();
        List<Long> teacherIds = ourseAddDto.getTeacharIds();
        //校验
        saveCheck(ourseAddDto);
        course.setLoginId(1L);
        course.setLoginUserName("xjj");
        course.setStatus(Course.STATUS_OFFLINE);
        List<Teacher> teachers = teacherMapper.selectBatchIds(teacherIds);
        StringBuilder stringBuilder = new StringBuilder();
        for (Teacher teacher : teachers) {
            String name = teacher.getName();
            stringBuilder=stringBuilder.append(name+",");
            course.setTeacherNames("stringBuilder");
        }
        if (course.getCourseTypeId()==null){
            throw new GlobalException("课程类型不能为空",null);
        }
        //保存课程
        insert(course);
        //保存营销表
        courseMarket.setId(course.getId());
        if (courseMarket.getPrice()==null ){
            courseMarket.setPrice(new BigDecimal(0));
        }
        marketService.insert(courseMarket);
        //保存详情表
        courseDetail.setId(course.getId());
        detailService.insert(courseDetail);
        //保存资源表
        courseResource.setCourseId(course.getId());
        resourceService.insert(courseResource);
        //初始化汇总表
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(course.getId());
        summaryService.insert(courseSummary);
        //保存老师的中间表
        teacherIds.forEach(teacherId->{
            CourseTeacher ct = new CourseTeacher();
            ct.setCourseId(course.getId());
            ct.setTeacherId(teacherId);
            courseTeacherService.insert(ct);
    });
    }

    @Override
    public void deleteByCode(String invitationCode) {
        EntityWrapper<Course> entityWrapper = new EntityWrapper<>();
        entityWrapper.eq("code",invitationCode);
        delete(entityWrapper);
    }

    /*课程上线*/
    @Override
    public void onLineCourse(Long id) {
        //1.如果id为空,抛异常
        if (id == null){
            throw new GlobalException("请求错误",null);
        }
        //2.如果点击已经发布的课程，抛出异常
        Course course = selectById(id);
        if (course == null)throw new GlobalException("请求错误",null);
        if (!course.getStatus().equals(Course.STATUS_OFFLINE))throw new GlobalException("课程已经上线",null);

        //3.设置上线状态，上线时间
        course.setStatus(Course.STATUS_ONLINE);
        course.setOnlineTime(new Date());
        updateById(course);

        //4.创建Doc对象，把相关对象的值赋值给DOC
        CourseDoc courseDoc = new CourseDoc();

        CourseMarket courseMarket = marketService.selectById(id);
        CourseSummary courseSummary = summaryService.selectById(id);

        BeanUtils.copyProperties(courseMarket,courseDoc);
        BeanUtils.copyProperties(courseSummary,courseDoc);
        BeanUtils.copyProperties(course,courseDoc);
        courseDoc.setChargeName(courseMarket.getCharge() ==1?"免费":"收费");

        //5.调用search的feign保存课程在Es
        JsonResult jsonResult = searchFeignClient.saveCourse(courseDoc);
        if (!jsonResult.isSuccess()){
            throw new GlobalException(jsonResult.getMessage(),null);
        }

        //发布消息
        publishMessage(course);
    }

    //下架
    @Override
    public void offLineCourse(Long id) {
        //1.如果id为空,抛异常
        if (id == null){
            throw new GlobalException("请求错误",null);
        }
        //2.如果点击已经下架的课程，抛出异常
        Course course = selectById(id);
        if (course == null)throw new GlobalException("请求错误",null);
        if (course.getStatus().equals(Course.STATUS_OFFLINE))throw new GlobalException("课程已经下线",null);

        //3.设置下线状态，下线时间
        course.setStatus(Course.STATUS_OFFLINE);
        course.setOnlineTime(new Date());
        updateById(course);

        //4.调用search的feign删除课程在Es
        JsonResult jsonResult = searchFeignClient.deleteCourse(id);
        if (!jsonResult.isSuccess()){
            throw new GlobalException(jsonResult.getMessage(),null);
        }
    }

    /*课程推荐,上线的*/
    @Override
    public void recommendCourse(Long courseId) {
        Course course = selectById(courseId);
        if (course.getStatus() !=Course.STATUS_ONLINE){
            throw new GlobalException("请推荐上线的课程",null);
        }
        int count = courseRecommendService.selectCount(new EntityWrapper<CourseRecommend>().eq("recom_state", CourseRecommend.STAUS_ISRECOMMEND));
        if (count>=5){
            throw new GlobalException("只能推荐5条课程",null);
        }
        EntityWrapper<CourseRecommend> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id",courseId);
        CourseRecommend courseRecommend = courseRecommendService.selectOne(wrapper);
        courseRecommend.setRecomState(1L);

        courseRecommendService.updateById(courseRecommend);

        List<Course> courseRecom =courseMapper.selcourseRecomByCourseId(courseId);

        redisTemplate.opsForValue().set(RedisConstant.RECOMMEND_COURSE_ON,courseRecom);
    }

    //前台获取课程推荐,上线的
    @Override
    public List<Course> getrecommendCourses() {
       // ArrayList<Course> RecommendCourseList = new ArrayList<>();
        List<Course> course = (List<Course>)redisTemplate.opsForValue().get(RedisConstant.RECOMMEND_COURSE_ON);
       // RecommendCourseList.add(course);
        return course;
    }
    //前台获取热门课程推荐,上线的
    @Override
    public List<Course> gethotRecommendClourses() {
        List<Course> list = (List<Course>) redisTemplate.opsForValue().get(RedisConstant.HOT_RECOMMEND_COURSE_ON);
        if (!StringUtils.isEmpty(list))return list;

        //查询热门前5条数据
        EntityWrapper<CourseSummary> query = new EntityWrapper<>();
        query.orderBy("view_count",false).last("limit 5");
        List<CourseSummary> courseList = summaryService.selectList(query);

        List<Long> ids = courseList.stream().map(courseSummary -> courseSummary.getId()).collect(Collectors.toList());

        List<Course> courses = selectBatchIds(ids);
        //List<Course> courseListFive = new ArrayList<>();
        redisTemplate.opsForValue().set(RedisConstant.HOT_RECOMMEND_COURSE_ON,courses,5, TimeUnit.SECONDS);

        return courses;
    }

    //获取课程详情
    @Override
    public CourseDetailDto getCourseDetailByCourseId(Long id) {
        //判断参数，
        AssertUtil.isNotNull(id,"课程ID为空,非法请求");
        //查询课程
        Course course = selectById(id);
        AssertUtil.isNotNull(course,"课程为空,非法请求");
        //条件：课程必须上线
        if (course.getStatus() != Course.STATUS_ONLINE){
            throw new GlobalException("课程没有上线",null);
        }
        //查询课程营销
        CourseMarket courseMarket = marketService.selectById(id);
        //查询课程详情
        CourseDetail courseDetail = detailService.selectById(id);
        //查询课程汇总
        CourseSummary courseSummary = summaryService.selectById(id);
        //查询老师列表
        List<Teacher> teachers = selectTeachersByCourseId(id);
        //查询章节列表
        List<CourseChapter> courseChapters = selectChaptersByCourseId(id);

        return new CourseDetailDto(course,courseMarket,courseDetail,courseSummary,courseChapters,teachers);
    }

    //根据课程id寻找章节,并把视频装进去
    private List<CourseChapter> selectChaptersByCourseId(Long courseId) {
        Wrapper<CourseChapter> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id",courseId);
        List<CourseChapter> courseChapters = chapterService.selectList(wrapper);
        //把章节List转成Map加快查询
        Map<Long, CourseChapter> courseChapterMap =
                courseChapters.stream().collect(Collectors.toMap(CourseChapter::getId, CourseChapter -> CourseChapter));
        //查询章节下的视频
        //1.media服务编写controller查询视频
        //2.编写api-media模块
        //3.课程整合api-media模块调用Feign接口，查询视频列表
        JsonResult jsonResult = mediaFeignClient.getByCourseId(courseId);
        //我希望你是true
        AssertUtil.isTrue(jsonResult.isSuccess(),jsonResult.getMessage());
        AssertUtil.isNotNull(jsonResult.getData(),"视频列表加载失败");
        //视频列表 : LinkedHashMap

        String json = JSON.toJSONString(jsonResult.getData());
        List<MediaFile> mediaFiles =  JSON.parseArray(json,MediaFile.class);

        mediaFiles.forEach(mediaFile -> {
            //播放地址设置为空
            mediaFile.setFileUrl("");
            CourseChapter courseChapter = courseChapterMap.get(mediaFile.getChapterId());
            if(courseChapter != null)courseChapter.getMediaFile().add(mediaFile);
        });

        //4.把视频列表，装到对应的章节里面
        return courseChapters;
    }

    //通过课程id获取老师
    private List<Teacher> selectTeachersByCourseId(Long courseId) {
        Wrapper<CourseTeacher> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id" ,courseId);
        //拿到课程和老师的中间对象
        List<CourseTeacher> courseTeachers = courseTeacherService.selectList(wrapper);
        //拿到老师ID
        List<Long> teacherIds = courseTeachers.stream().map(CourseTeacher::getTeacherId).collect(Collectors.toList());
        //查询老师列表
        return teacherMapper.selectBatchIds(teacherIds);
    }

    //返回前端订单的详情页面
    @Override
    public CourseDataForOrderVO selCourseForOrder(String courseStrIds) {
        if (StringUtils.isEmpty(courseStrIds)){
            throw new GlobalException("课程id为空,非法请求",null);
        }

        List<Long> Ids = StrUtils.splitStr2LongArr(courseStrIds);

        List<Course> courses = selectBatchIds(Ids);

        if (StringUtils.isEmpty(courses)){
            throw new GlobalException("课程id为空,非法请求",null);
        }

        if (courses.size() != Ids.size()){
            throw new GlobalException("课程id为空,非法请求",null);
        }
//todo
        //获取营销表
        List<CourseMarket> courseMarkets = marketService.selectBatchIds(Ids);

        //把营销转成map
        Map<Long, CourseMarket> marketCollect = courseMarkets.stream().collect(Collectors.toMap(CourseMarket::getId, CourseMarket -> CourseMarket));
        //小的VO
        ArrayList<CourseOrderDataitemVO> ItemVOList = new ArrayList<>(Ids.size());

        BigDecimal totalAmount = new BigDecimal("0");
        for (Course cours : courses) {
            CourseMarket courseMarket = marketCollect.get(cours.getId());
            //判断是否上线和免费
            if (courseMarket.getCharge() != CourseMarket.CHARGE_NO_FREE){
                throw new GlobalException("课程有免费的",null);
            }
            if (cours.getStatus() != Course.STATUS_ONLINE){
                throw new GlobalException("课程不是上线的",null);
            }

            ItemVOList.add(new CourseOrderDataitemVO(cours,courseMarket));
            totalAmount = totalAmount.add(courseMarket.getPrice());
        }
        //大的VO
        return new CourseDataForOrderVO(ItemVOList,totalAmount);
    }

    //查询课程状态
    @Override
    public CourseStateVO selectCourseStatusForUser(Long courseId) {
        //根据课程ID查询课程的状态： 是否免费，是否购买，是否上线
        AssertUtil.isNotNull(courseId,"课程ID不能为空");
        Course course = selectById(courseId);
        AssertUtil.isNotNull(course,"课程为空");
        //查询课程营销
        CourseMarket courseMarket = marketService.selectById(courseId);
        AssertUtil.isNotNull(courseMarket,"课程为空");

        //登录对象
        Long loginId = 3l; //todo，先玩一个假的，后面做了登录来改

        //判断是否免费
        boolean isFree = (courseMarket.getCharge() != null && courseMarket.getCharge() == CourseMarket.CHARGE_FREE);
        //是否上线
        boolean isOnline = course.getStatus() == Course.STATUS_ONLINE;
        //是否购买
        boolean isBuyed = (null != selectByUserIdAndCourseId(loginId,courseId));

        CourseStateVO courseStatus = new CourseStateVO();
        courseStatus.setFree(isFree);
        courseStatus.setOnline(isOnline);
        courseStatus.setPurchased(isBuyed);

        return courseStatus;
    }

    private CourseUserLearn selectByUserIdAndCourseId(Long loginId, Long courseId) {
        Wrapper<CourseUserLearn> wrapper = new EntityWrapper<>();
        wrapper.eq("login_id" , loginId);
        wrapper.eq("course_id" , courseId);
        wrapper.eq("state",0);//查询有效的
        return learnService.selectOne(wrapper);
    }

    private void publishMessage(Course course) {
        String content ="亲,最新课程 %s 发布了<a href='http://tcc.ui.user/detial.html?courseId=%s'>点击</a>";
        content= String.format(content,course.getName(),course.getId());
        StationMessage2MQDto stationMessage2MQDto = new StationMessage2MQDto("课程发布", content, "课程消息", Arrays.asList(1L, 2L));

        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(stationMessage2MQDto)).build();
        SendResult sendResult = mQTemplate.syncSend(MQConstants.TOPIC_STATION_FILE + ":" + MQConstants.TAGS_STATION_FILE, message);
        log.info("站内信推送 {}",sendResult);
    }

    public void saveCheck(CourseAddDto ourseAddDto) {
        EntityWrapper<Course> wrapper = new EntityWrapper<>();
        wrapper.eq("name",ourseAddDto.getCourse().getName());
        Course course1 = selectOne(wrapper);
        if (!StringUtils.isEmpty(course1))throw new GlobalException("课程名字重复了",null);
    }
}
